﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnviamentDeDocuments.ObjectesDeDades;
using EnviamentDeDocuments.ObjectesDeDades.TDiariExpedDadesVariablesDataSetTableAdapters;
using EnviamentDeDocuments.Formularis;
using System.Windows.Forms;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using System.Xml;
using System.Xml.XPath;
using System.Net.Mail;
using System.Web;
using System.Net;

namespace EnviamentDeDocuments.ObjectesDeNegoci
{
    class ProcessarEnviamentController : Controller
    {

        public List<Client> ClientsSeleccionats { get; set; }
        public List<Impost> ImpostosSeleccionats { get; set; }
        public List<Periode> PeriodesSeleccionats { get; set; }
        public Exercici ExerciciSeleccionat { get; set; }

        private List<Client> ClientsSeleccionatsValids;
        frmProces frm;
        System.Threading.Thread th;

        public override void run()
        {
            ClientsSeleccionatsValids = (from Client c in ClientsSeleccionats where c.Valid select c).ToList<Client>();

            frm = new frmProces();
            frm.ValorMaximBarraProgres = ClientsSeleccionatsValids.Count;

            th = new System.Threading.Thread(Processa);
            th.Start();

            frm.ShowDialog();

            if (frm.Continuar)
                ProximaAccio = enumProximaAccio.ProximPas;
            else
                ProximaAccio = enumProximaAccio.AnteriorPas;

            th.Abort();

        }

        private void Processa()
        {
            int i = 1;

            foreach (Client c in ClientsSeleccionatsValids)
            {
                try
                {
                    //Si s'ha apretat cancel·lar, ho aturem tot.
                    if (frm.CancelContinuePressed) 
                    { 
                        frm.Estat = frmProces.EstatEnviament.Aturat; 
                        frm.CancelContinuePressed = false;
                        //Quedem a l'espera de que es premi continuar
                        while  (!frm.CancelContinuePressed)
                            System.Threading.Thread.Sleep(1000);

                        frm.Estat = frmProces.EstatEnviament.Enviant; 
                        frm.CancelContinuePressed = false;
                    }

                    int numDocs = 0;
                    String observacions = "";

                    frm.setInfoAccioActual("Processant client " + i + " de " + ClientsSeleccionatsValids.Count + " - " + c.ToString());
                    EnviaCorreu(c, out numDocs, out observacions);
                    frm.addGridRow(c.Nom, numDocs, observacions);
                    frm.AvancaBarraProgres();

                    System.Threading.Thread.Sleep(1);
                    i++;
                }
                catch (System.Threading.ThreadAbortException)
                {
                    return;
                }
                catch (Exception e)
                {
                    frm.setInfoAccioActual("S'ha produit un error - " + e.Message + Environment.NewLine + e.StackTrace);
                    return;
                }
            }

            frm.Estat = frmProces.EstatEnviament.Acabat; 
        }

        private bool EnviaCorreu(Client c,  out int documentsAdjunts, out string observacions)
        {
            documentsAdjunts = 0;

            if (String.IsNullOrEmpty(c.Email))
            {
                observacions = "El client no té un email vàlid";
                return false;
            }

            Stream stream = new MemoryStream();
            List<Document> documents;

            if (!PrepararArxiuZip(c, stream, out documents, out observacions)) return false;            
            if (!PrepararCorreu(c, stream, documents, out observacions)) return false;

            documentsAdjunts = documents.Count;

            return true;
        }

        #region Arxiu ZIP

        private bool PrepararArxiuZip(Client c, Stream ms, out List<Document> documents, out string observacions)
        {
            documents = new List<Document>();
            observacions = "";

            if (!Directory.Exists(Properties.Settings.Default.pathToArxiuFolder + "\\" + c.Nom + " - " + c.Nif)) { observacions = "No s'ha trobat la carpeta del client"; return false; }
            if (!Directory.Exists(Properties.Settings.Default.pathToArxiuFolder + "\\" + c.Nom + " - " + c.Nif + "\\Impostos\\")) { observacions = "No s'ha trobat la carpeta d'impostos del client"; return false; }
            if (!Directory.Exists(Properties.Settings.Default.pathToArxiuFolder + "\\" + c.Nom + " - " + c.Nif + "\\Impostos\\" + ExerciciSeleccionat.Any)) { observacions = "No s'ha trobat la carpeta de l'exercici " + ExerciciSeleccionat.Any; return false; }

            ZipFile zip = ZipFile.Create(ms);

            zip.BeginUpdate();
            zip.Password = c.Nif.ToUpper();

            foreach (Impost imp in ImpostosSeleccionats)
            {
                if (!Directory.Exists(Properties.Settings.Default.pathToArxiuFolder + "\\" + c.Nom + " - " + c.Nif + "\\Impostos\\" + ExerciciSeleccionat.Any + "\\" + imp.Codi))
                {
                    observacions = "No s'ha trobat la carpeta de l'impost " + imp.Codi;
                    continue;
                }
                else
                {
                    String ImpostosFolder = Properties.Settings.Default.pathToArxiuFolder + "\\" + c.Nom + " - " + c.Nif + "\\Impostos\\" + ExerciciSeleccionat.Any + "\\" + imp.Codi;                    
                    switch (imp.Codi.ToUpper())
                    { 
                        case "INTRASTAT":
                            //L'intrastat va diferent que la resta
                            foreach (String FolderName in Directory.GetDirectories(ImpostosFolder))
                            {
                                String NomDirectori = FolderName.Split("\\".ToCharArray()).Last();
                                if (NomDirectori.Length < 7) continue;

                                Periode periodeDocument = (from Periode p in PeriodesSeleccionats where p.Codi == NomDirectori.Substring(0, 2) && ExerciciSeleccionat.ToString() == NomDirectori.Substring(3,4)  select p).FirstOrDefault();
                                if (periodeDocument != null)
                                {
                                    foreach (String FileName in Directory.GetFiles(FolderName))
                                    {
                                        String NomFitxer = FileName.Split("\\".ToCharArray()).Last();
                                        if (NomFitxer.Length < 3) continue;

                                        String NomFitxerAEnviar = GeneraNomFitxerAEnviar(NomFitxer, imp, periodeDocument, ExerciciSeleccionat, c);
                                        documents.Add(new Document() { client = c, periode = periodeDocument, exercici = ExerciciSeleccionat, impost = imp, nomFitxer = NomFitxerAEnviar });
                                        zip.Add(FileName, NomFitxerAEnviar);
                                    }
                                }
                            }
                            break;
                        default:
                            foreach (String FileName in Directory.GetFiles(ImpostosFolder))
                            {
                                String NomFitxer = FileName.Split("\\".ToCharArray()).Last();
                                if (NomFitxer.Length < 7) continue;

                                Periode periodeDocument = (from Periode p in PeriodesSeleccionats where p.Codi == NomFitxer.Substring(5, 2) select p).FirstOrDefault();
                                if (periodeDocument != null)
                                {
                                    String NomFitxerAEnviar = GeneraNomFitxerAEnviar(NomFitxer, imp, periodeDocument, ExerciciSeleccionat, c); 
                                    documents.Add(new Document() { client = c, periode = periodeDocument, exercici = ExerciciSeleccionat, impost = imp, nomFitxer = NomFitxerAEnviar });
                                    zip.Add(FileName, NomFitxerAEnviar);
                                }
                            }
                            break;
                    }
                }
            }

            zip.CommitUpdate();
            zip.Close();

            if (documents.Count == 0) 
            { 
                observacions = "No s'han trobat documents que compleixin els criteris seleccionats"; 
                return false; 
            }
            else 
                return true;

        }

        private String GeneraNomFitxerAEnviar(String NomFitxer, Impost imp, Periode periodeDocument, Exercici ExerciciSeleccionat, Client c)
        {
            //imp.Codi + "_" + ExerciciSeleccionat.ToString() + "_" + periodeDocument.Codi + "." + NomFitxer.Substring(NomFitxer.Length - 3, 3);
            if (NomFitxer.Contains(c.Nif))
            {
                return NomFitxer.Substring(0, NomFitxer.IndexOf(c.Nif) - 1) + NomFitxer.Substring(NomFitxer.IndexOf(c.Nif) + c.Nif.Length, NomFitxer.Length - NomFitxer.IndexOf(c.Nif) - c.Nif.Length);
            }
            else
                return NomFitxer;
        }

        #endregion

        #region Preparació del correu

        private string Subject { get; set; }
        private string From { get; set; }
        private string BodyTemplate { get; set; }
        private string RowTemplate { get; set; }

        private bool PrepararCorreu(Client c, Stream ms, List<Document> documents, out string observacions)
        {
            SmtpClient smtp = null;
            MailMessage msg = null;

            try
            {
                ReadConfig("./Templates/ImpostosMailTemplate.xml");
                msg = BuildMessage(c, ms, documents);

                smtp = new SmtpClient(Properties.Settings.Default.mailServer, Properties.Settings.Default.mailPort);
                smtp.EnableSsl = Properties.Settings.Default.mailUseSSL;
                smtp.Credentials = new System.Net.NetworkCredential(Properties.Settings.Default.mailUser, Properties.Settings.Default.mailPassword);
                smtp.Send(msg);

                observacions = "OK";
                return true;
            }
            catch (Exception e)
            {
                observacions = "S'ha produit un error en el procés d'enviament del correu. L'error ha estat: " + e.Message + Environment.NewLine + e.StackTrace;
                return false;
            }
            finally
            {
                if (msg != null) msg.Dispose();
                if (smtp != null) smtp.Dispose();
            }
        
        }

        private void ReadConfig(string cfgFile)
        {
            using (StreamReader sr = new StreamReader(cfgFile))
            {
                XPathDocument doc = new XPathDocument(sr);
                XPathNavigator Nav = doc.CreateNavigator();

                Subject = Nav.SelectSingleNode("ImpostosMailTemplate/MailSubject").InnerXml;
                From = Nav.SelectSingleNode("ImpostosMailTemplate/MailFrom").InnerXml;
                BodyTemplate = Nav.SelectSingleNode("ImpostosMailTemplate/MailBody").InnerXml;
                RowTemplate = Nav.SelectSingleNode("ImpostosMailTemplate/DocumentRow").InnerXml;
            }
        }

        private MailMessage BuildMessage(Client c, Stream ms, List<Document> documents)
        {
            MailMessage msg = new MailMessage();
            String body = BuildBody(c, documents);

            LinkedResource logo = new LinkedResource("./Templates/logo.gif", System.Net.Mime.MediaTypeNames.Image.Gif) { ContentId = "logo" };
            AlternateView htmlView = AlternateView.CreateAlternateViewFromString(body, new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Html));
            htmlView.LinkedResources.Add(logo);
            msg.AlternateViews.Add(htmlView);
            
            string[] adreces = {c.Email};

            msg.From = new MailAddress(this.From);
            msg.Subject = this.Subject;

            ms.Seek(0, SeekOrigin.Begin);
            System.Net.Mail.Attachment attach = new Attachment(ms, new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Application.Zip));
            attach.Name = "Impostos.zip";
            msg.Attachments.Add(attach);

            foreach (string addr in adreces)
            {
                msg.To.Add(new MailAddress(addr));
            }

            return msg;
        }

        private string BuildBody(Client c, List<Document> documents)
        {
            string Resultat = WebUtility.HtmlDecode(this.BodyTemplate);
            string Rows = "";

            foreach (Document document in documents)
            {
                string Fila = WebUtility.HtmlDecode(this.RowTemplate);

                Fila = Fila.Replace("$(IMPOST)", WebUtility.HtmlEncode(document.impost.Nom));
                Fila = Fila.Replace("$(PERIODE)",  WebUtility.HtmlEncode(document.periode.Nom));
                Fila = Fila.Replace("$(EXERCICI)",  WebUtility.HtmlEncode(document.exercici.ToString()));
                Fila = Fila.Replace("$(NOMFITXER)", WebUtility.HtmlEncode(document.nomFitxer));

                Rows += Fila;
            }

            Resultat = Resultat.Replace("$(DOCUMENTS)", Rows);
            Resultat = Resultat.Replace("$(CONTACTE)", c.Contacte);
            Resultat = Resultat.Replace("$(EMPRESA)", c.Nom);

            return Resultat;
        }

        #endregion
    }
}
